const slime_core           = require("../../annotation/index.js");

const slime_member_sources = @options("sources") || {};

const slime_member_model    = require("../../library/member.js");
const slime_member_fields   = @.keys(slime_member_model);

module.exports = function(lab) {
    return {
        // 获取当前用户的member对象
        "currentMember": function(session) {
            return lab.slime.member.@initSession(session);
        },
        "@getSourcesByOUID" : function (ouid) {
            return lab.find("backend_operation_units",ouid).then(function (backendOU) {
                if (backendOU.suffix){
                    return @.async.resolve(Object.keys(slime_member_sources).filter(function (source) {
                        return slime_member_sources[source] == backendOU.suffix;
                    }));
                } else {
                    this.next([]);
                }
            });
        },
        // 根据id获取主member
        "@getMember": function(id) {
            return lab.find("slime_member_ids", id).then(function(member_id) {
                if (member_id && member_id.main_id && member_id.id !== member_id.main_id) {
                    return lab.find("slime_member_ids", member_id.main_id)
                } else {
                    this.next(member_id);
                }
            }).then(function(member_id) {
                lab.find("slime_members", member_id.id).then(function (member) {
                    this.next(member,member_id);
                }).pipe(this);
            })
        },
        "@getMemberBySourceID" : function (id, idSource) {
            if (!id || !idSource){
                throw @lab.errors.invalid_parameters;
            }
            var idSourceQuery = {};
            idSourceQuery[`${idSource.split(".").join("_")}_id`] = id;
            return lab.find("slime_member_ids",idSourceQuery).then(function (member_id) {
                if (member_id) {

                    @.async(function () {

                        if (member_id.main_id && member_id.id !== member_id.main_id) {
                            return lab.find("slime_member_ids", member_id.main_id)
                        } else {
                            this.next(member_id);
                        }

                    }).then(function(member_id) {

                        lab.find("slime_members", member_id.id).then(function (member) {
                            this.next(member,member_id);
                        }).pipe(this);
                        
                    }).pipe(this);

                } else {
                    throw @lab.errors.object_not_found;
                }
            })
        },
        "@getMemberID": function(id, idSource) {
            return lab.find("slime_member_ids", id).then(function(member_id) {
                if (member_id && member_id.main_id && member_id.id !== member_id.main_id) {
                    return lab.find("slime_member_ids", member_id.main_id)
                } else {
                    this.next(member_id);
                }
            }).then(function(member_id) {
                
                if (member_id && idSource) {

                    if (["email","phone"].indexOf(idSource) < 0){
                        this.next(member_id[`${idSource.split(".").join("_")}_id`]);
                    } else {
                        this.next(member_id[idSource]);
                    }
                    
                } else {
                    this.next(member_id);
                }
            })
        },
        // 更新member对象
        "@updateMember": function(update_form, { idSource, idField, idValue, idOwnerOU, idMain }) {
            // 没有idSource的话initSession肯定报错
            

            if (!idValue) {
                throw @lab.errors.invalid_parameters;
            }
            

            return @.async(function (params) {

                return lab.slime.member.@queryMember({ idValue, idField, idSource, idOwnerOU})

            }).then(function(mapping, currentOU) {

                this.pool.currentOU = currentOU;

                if (mapping) {

                    this.next(mapping);

                } else {
                    let queryForm = {}

                    // 这里创建一个新的member对象

                    if (idOwnerOU && idField) {
                        queryForm[idField] = idValue;
                    } else if (['phone','email'].indexOf(idSource) >= 0){
                        queryForm[idSource] = idValue;
                    } else {
                        queryForm[idSource.split(".").join("_") + '_id'] = idValue;
                    }

                    queryForm.ouid = currentOU.id;
                    queryForm.last_update = Date.now();

                    if (idMain) {
                        queryForm.main_id = idMain;
                        queryForm.id = @.uuid();
                    } else {
                        queryForm.main_id = @.uuid();
                        queryForm.id = queryForm.main_id;
                    }

                    lab.createWithoutCache("slime_member_ids",queryForm).pipe(this);
                }

            }).then(function(mapping) {

                this.pool.mapping = mapping;
                lab.find("slime_members", mapping.id).pipe(this)

            }).then(function(member) {

                if (member) {
                    this.next(member, false)
                } else {

                    return lab.create("slime_members", {
                        id: this.pool.mapping.id,
                        ouid: this.pool.currentOU.id,
                        is_removed: false,
                        create_date: Date.now(),
                    }).then(function(created_member) {

                        if (!idMain){
                            process.nextTick(function() {
                                @mew.auto("slime.member_created", {member : created_member});
                            })
                        }
                        
                        this.next(created_member, true);
                    });
                }

            }).then(function(member, create_flag) {

                // HD TODO : 记录一下变更内容；
                // 这里就根据update_form的因素，来判断是否变更；
                // 要处理来自于不同source的字段权限；

                // idSource
                // 1. 更新数据
                // 2. 合并数据

                // 微信的字段 -> Godiva的POS中乱码了。
                // 微信来的用户 -> 修改了一个不应该他有权限修改的字段，导致的结果。
                // 这个东西应该是一个策略去管理的，来自不同的数据源，数据的归并方案；
                // nickname这个名字；
                // 地区是瞎填的，那么这个数据源的字段就不应该

                var the_member_id = this.pool.mapping;
                
                if (!update_form) {
                    return this.next(member, the_member_id);
                }

                if (!idSource) {
                    return lab.update("slime_members", member, update_form, {
                        last_update: Date.now()
                    }).then(function (updated_member) {
                        this.next(updated_member, the_member_id);
                    });
                }
                
                return lab.sqlite.find("slime_member_updates", {
                    member_id: member.id,
                    source_id: idSource
                }, 1, 0, ["create_date", "desc"]).then(function({ records }) {
                    if (records.length) {
                        this.next(records[0]);
                    } else {
                        this.next();
                    }
                }).then(function(last_update) {
                    // last_update

                    var updated_fields = slime_member_fields.filter(function(field_name) {
                        if (last_update) {
                            return update_form[field_name] && (!member[field_name] || update_form[field_name] != last_update[field_name]);
                        } else {
                            return true;
                        }
                    });

                    if (updated_fields.length) {

                        lab.create("slime_member_updates", @.merge.simple(update_form, {
                            updated_fields: updated_fields,
                            member_id: member.id,
                            source_id: idSource,
                            create_date: Date.now()
                        })).resolve(updated_fields).pipe(this);

                    } else {
                        this.next();
                    }

                }).then(function(updated_fields) {

                    if (updated_fields) {
                        // return lab.update("slime_members", member,update_form);
                        // source的写权限，去判断是否可以写入这个字段；
                        // TODO: 增加一个接口去新增规则
                        return lab.find("slime_member_update_settings", {
                            ouid: member.ouid,
                            source_id: idSource,
                        }).then(function(settings) {

                            if (settings) {
                                this.next(updated_fields.filter(function(field) {
                                    return settings[field];
                                }));
                            } else {
                                this.next(updated_fields);
                            }

                        }).then(function(update_data_fields) {

                            if (update_data_fields.length) {

                                return lab.update("slime_members", member, update_data_fields.reduce(function(update_data, field) {
                                    update_data[field] = update_form[field];
                                    return update_data;
                                }, {}), {
                                    last_update: Date.now()
                                }).then(function(updated_member) {

                                    if (!create_flag && !idMain) {
                                        process.nextTick(function() {
                                            @mew.auto("slime.member_updated", updated_member);
                                        });
                                    }
                                    this.next(updated_member , the_member_id);
                                });

                            } else {
                                this.next(member, the_member_id);
                            }

                        });

                    } else {
                        this.next(member,the_member_id);
                    }

                })

            })
        },
        // 电话号码获得会员
        "@phoneUpdateMember": function(phone, source, source_id) {
            if (!phone){
                throw @lab.errors.invalid_parameters;
            }
            if (!(source && source_id) && !slime_member_sources.phone){
                throw @lab.errors.invalid_parameters;
            }

            return lab.slime.member.@updateMember({ phone }, {
                idSource: source ? source : 'phone',
                idField : source_id ? undefined : 'phone',
                idValue: source_id || phone
            });
        },

        // 合并会员
        "@mergeMember": function(mainMember, targetMember) {
            if (mainMember.ouid !== targetMember.ouid) {
                throw @lab.errors.member_ou_different;
            }
            return lab.sqlite.query.apply(lab.sqlite, ["update slime_member_ids set main_id = ? where main_id = ?", mainMember.id, targetMember.id]).then(function() {

                slime_member_fields.forEach(function(field) {
                    if (!mainMember[field] && targetMember[field]) {
                        mainMember[field] = targetMember[field]
                    }
                });

                mainMember.last_update = Date.now()

                process.nextTick(function() {
                    @mew.auto("slime.member_merged", {
                        mainMember,
                        targetMember
                    });
                });

                lab.update("slime_members", mainMember).pipe(this)
                
            }).then(function() {

                lab.update("slime_members",targetMember,{
                    is_removed : true
                }).pipe(this);

            }).then(function() {

                lab.find("slime_member_ids", mainMember.id).pipe(this);

            }).then(function(mainMemberID) {

                return lab.find("slime_member_ids", targetMember.id).then(function(targetMemberID) {

                    @.keys(slime_member_sources).map(function(source) {
                        return source.split(".").join("_") + "_id";
                    }).concat(["uid", "phone", "email"]).forEach(function(key) {
                        if (!mainMemberID[key] && targetMemberID[key]) {
                            mainMemberID[key] = targetMemberID[key]
                        }
                    })

                    return lab.update("slime_member_ids", mainMemberID)
                })
            })
        },


        "@fakeSession": function(member_id) {

            return lab.find("slime_members", member_id).then(function(currentMember) {
                if (currentMember) {
                    this.next(currentMember);
                } else {
                    throw @lab.errors.object_not_found;
                }
            });

        },

        /**
         * 根据idSource 和 idOwnerOU 确定 会员所属组织
         * 
         */
        "@queryMember": function({ idSource, idField, idValue, idOwnerOU }) {

            if (!idValue){
                throw @lab.errors.invalid_parameters;
            }

            return @.async(function() {
                if (idOwnerOU && idField) {
                    this.next(idOwnerOU)
                } else if (idSource && slime_member_sources[idSource]) {
                    return lab.slime.core.@initSession({}, slime_member_sources[idSource])
                } else {
                    throw @lab.errors.invalid_parameters;
                }
            }).then(function(currentOU) {

                let queryForm = {}
                if (idField && idOwnerOU) {
                    queryForm[idField] = idValue;
                } else if (['phone','email'].indexOf(idSource) >= 0){
                    queryForm[idSource] = idValue;
                } else {
                    queryForm[idSource.split(".").join("_") + "_id"] = idValue;
                }

                queryForm.ouid = currentOU.id
                return lab.find("slime_member_ids", queryForm).then(function(member_id) {

                    if (member_id && member_id.main_id && member_id.id !== member_id.main_id) {

                        lab.find("slime_member_ids", member_id.main_id).then(function (main_member_id) {
                            this.next(main_member_id, currentOU);
                        }).pipe(this);

                    } else {
                        this.next(member_id, currentOU);
                    }

                })
            })
        },
        
        // 纯只读的接口
        "@initSession": function(session) {
            
            if (session.currentMember) {

                return @.async.resolve(session.currentMember);

            } else {

                return @.async(function () {

                    var lockID      = "slime.member.session." + session.id;
                    var lockTimeout = 100;

                    var lockHandler = function () {

                        return @.async.all(@.keys(slime_core.sources),function (coreSource) {
                            @.async.ensure(slime_core.sources[coreSource].detector(lab , session)).finished((error, result) => {

                                if (error) {
                                    @error(error);
                                    this.next();
                                } else if (result && result.idValue) {

                                    this.next({
                                        idSource   : coreSource,
                                        idValue    : result.idValue,
                                        memberData : result.memberData,
                                        idField    : `${coreSource.split(".").join("_")}_id`
                                    });

                                } else {
                                    this.next();
                                }

                            })

                        }).then(function (coreSourceQueries) {
                            var filteredQueries = coreSourceQueries.filter((query) => { return query;});

                            if (filteredQueries.length == 0) {
                                throw @lab.errors.not_login;
                            } else {

                                var ownerIdentity = slime_member_sources[filteredQueries[0].idSource];

                                if (!filteredQueries.reduce(function (check, {idSource}) {
                                    return check && ownerIdentity == slime_member_sources[idSource];
                                },true)) {
                                    throw new Error("Member Source not from Same ou");
                                } else {

                                    lab.slime.core.@initSession({}, ownerIdentity).then(function (currentMemberOU) {

                                        session.currentMemberOU = currentMemberOU;

                                        lab.sqlite.find("slime_member_ids", {
                                            "ouid" : currentMemberOU.id,
                                            "!" : ["(" + filteredQueries.map(function (query) {
                                                return `${query.idField} == ?`
                                            }).join(") || (") + ")", ...filteredQueries.map((query) => query.idValue)]
                                        }).pipe(this);

                                    }).then(function ({records}) {

                                        this.next(filteredQueries.reduce(function (result, {idValue, idField, idSource, memberData}) {

                                            var idMember = records.find((member_id) => member_id[idField] == idValue);

                                            if (idMember) {

                                                result.idMembers[idMember.id]   = idMember;
                                                if (result.idMemberMap[idMember.main_id]){
                                                    result.idMemberMap[idMember.main_id].push(idMember);
                                                } else {
                                                    result.idMemberMap[idMember.main_id] = [idMember];
                                                }

                                            } else {
                                                result.newMembers.push({idSource, idField, idValue, memberData});
                                            }
    
                                            return result;
                                        },{idMembers : {}, idMemberMap : {} , newMembers : []}));
    
                                    }).then(function ({idMembers , idMemberMap, newMembers }) {
                                        var mainID;
                                        var mainIDCandidates = @.keys(idMemberMap);

                                        if (mainIDCandidates.length == 1){
                                            mainID = mainIDCandidates[0];
                                        } else if (mainIDCandidates.length > 1) {
                                            mainID = mainIDCandidates.sort(function (mainIDA, mainIDB) {
                                                return idMemberMap[mainIDB].length - idMemberMap[mainIDA].length;
                                            })[0];
                                        }

                                        if (!mainID) {
                                            return this.next({idMembers ,idMemberMap, newMembers});
                                        }

                                        if (idMembers[mainID]) {
                                            this.next({idMain : idMembers[mainID], idMembers , idMemberMap, newMembers});
                                        } else {
                                            lab.find("slime_member_ids",mainID).then(function (idMain) {
                                                this.next({idMain, idMembers , idMemberMap, newMembers});
                                            }).pipe(this);
                                        }

                                    }).then(function ({idMain, idMembers , idMemberMap, newMembers }) {
                                        @.async.all(newMembers,function ({idSource, idField, idValue , memberData}) {
                                            lab.slime.member.@updateMember(memberData, {
                                                idMain : (idMain ? idMain.id : null) ,idSource,idField,idValue, idOwnerOU:session.currentMemberOU
                                            }).then(function (createdMember, createdMemberID) {

                                                if (idMemberMap[createdMember.main_id]){
                                                    idMemberMap[createdMember.main_id].push(createdMemberID);
                                                } else {
                                                    idMemberMap[createdMember.main_id] = [createdMemberID];
                                                }

                                                idMembers[createdMemberID.id] = createdMemberID;
                                                this.next(createdMember);

                                            }).pipe(this);

                                        }).then(function (createdMembers = []) {
                                            if (idMain) {
                                                return @.async(function () {
                                                    lab.find("slime_members", idMain.id).pipe(this);
                                                }).then(function (mainMember) {
                                                    @.async.all(createdMembers,function (newMember) {
                                                        return lab.slime.member.@mergeMember(mainMember,newMember);
                                                    }).resolve(mainMember).pipe(this);
                                                })

                                            } else if (createdMembers.length == 1) {
                                                this.next(createdMembers[0]);
                                            } else if (createdMembers.length > 1) {

                                                let mainMember = createdMembers.shift();
                                                @.async.all(createdMembers,function (newMember) {
                                                    return lab.slime.member.@mergeMember(mainMember,newMember);
                                                }).resolve(mainMember).pipe(this);

                                            } else {
                                                throw @lab.errors.not_support;
                                            }
                                            
                                        }).pipe(this);
                                    }).pipe(this);
                                }
                            }
                        });
                    }

                    @.async(function (params) {
                        if (lab.redis.client) {
                            lab.redis.client.lock(lockID ,lockTimeout, function(){
                                return lockHandler()
                            }).pipe(this);
                        } else {
                            @.lock(lockID, lockTimeout , lockHandler).pipe(this);
                        }
                    }).finished((error, mainMember) => {
                        if (error) {
                            @error(error);
                            this.reject(@lab.errors.not_login);
                        } else {
                           
                            session.currentMember = mainMember;

                            if (session.currentMember) {
                                process.nextTick(function () {
                                    @mew.auto("slime.member_accessed",{member : mainMember});
                                })
                            }
                            
                            this.next(mainMember);
                        }
                    });

                })
            }
        },
        "@importMember": function({ member, source }) {

            return @.async(function() {

                if (source && member.id && slime_member_sources[source]) {

                    lab.slime.member.@updateMember(member || {}, {
                        idSource: source,
                        idValue: member.id
                    }).pipe(this);

                } else if (member && member.phone) {

                    lab.slime.member.@phoneUpdateMember(member.phone, source, member.id || member.phone).pipe(this);

                } else {
                    throw @lab.errors.invalid_parameters;
                }

            }).then(function(result) {

                result.is_removed = false;

                @.keys(slime_member_model).forEach(function(key) {
                    if (member[key]) {
                        result[key] = member[key]
                    }
                })

                result.last_update = Date.now()
                lab.update("slime_members", result).pipe(this)

            })
        }
    }
}